/**
  ******************************************************************************
  * Copyright(c) 2018-2023 WUHAN LEADOR All rights reserved. 
  * - Filename    
  * - Author  Vincent
  * - Version V1.0.0
  * - Date    2019/4/16
  * - Brief   
  * - FunctionList:
  ******************************************************************************
  * History:
  *   
  *
  * 
  ******************************************************************************
*/

/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include <getopt.h>
#include <netdb.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include "socket_server.h"
#include "event_pool.h"
#include "socket_server_util.h"
#include "dbg.h"

/* prama define discrible -----------------------------------------------------*/
#define MAX_BUF 4096

/* strcuct  discrible --------------------------------------------------------*/
typedef struct
{
  /* data */
  void *root;
  int connfd;
  int epvfd;
  char rec_buf[MAX_BUF];
  int status;
} socket_connect_obj_t;

typedef socket_connect_obj_t sco_t;
/* prama  discrible ---------------------------------------------------------*/

/* private fucntion  declaration --------------------------------------------*/

/* private fucntion  discrible -----------------------------------------------*/
int socket_connect_obj_init(sco_t *sco, int connfd, int epvfd);
int socket_connect_obj_free(sco_t *sco);
/*------------------------------------ ----------------------------------------
- @Name:  
- @Discrible:   
- @Param:  
- @Return:   
- @Others: 
------------------------------------ ----------------------------------------
- @Recode    date       version	        author             modify 
-          ------------------------------------------------------------------
-          20190416      V1.0          VINCENT            Create
- 
------------------------------------ ----------------------------------------*/
void socket_server_start(void)
{
  int listen_port = 8000;
  int listenfd, rc;
  struct sockaddr_in clientaddr;

  /*
  * bind listen poet
  */
  listenfd = open_listenfd(listen_port);
  rc = make_socket_non_blocking(listenfd);

  /*
  * create epoll and add listenfd to ep
  */
  int epfd = ep_create(0);
  struct epoll_event event;

  sco_t *socket_connect = (sco_t *)malloc(sizeof(sco_t));
  socket_connect_obj_init(socket_connect, listenfd, epfd);

  event.data.ptr = (void *)socket_connect;
  event.events = EPOLLIN | EPOLLET;

  ep_add(epfd, listenfd, &event);

  int timeout = 10;
  int event_count, i;
  while (1)
  {
    event_count = epoll_wait(epfd, events, MAXEVENTS, timeout);
    for (i = 0; i < event_count; i++)
    {
      sco_t *sco = (sco_t *)events[i].data.ptr;
      /* 如果返回的事件错误或超时或不是刻度事件，则关闭绑定的文件描述符 */
      if ((events[i].events & EPOLLERR))
      {
        /* An error has occured on this fd, or the socket is not
          ready for reading (why were we notified then?) */
        log_err("epoll error，err fd: %d\n", sco->connfd);
        close(sco->connfd);
        continue;
      }
      /*如果返回监听端口描述符，说明有链接到来，并建立Socket链接*/
      else if (sco->connfd == listenfd)
      {
        while (1)
        {
          struct sockaddr in_addr;
          socklen_t in_len;
          int infd;
          char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

          in_len = sizeof(in_addr);
          infd = accept(sco->connfd, &in_addr, &in_len);
          if (infd == -1)
          {
            if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
            {
              break;
            }
            else
            {
              perror("accept");
              break;
            }
          }

          if (!getnameinfo(&in_addr, in_len,
                           hbuf, sizeof hbuf,
                           sbuf, sizeof sbuf,
                           NI_NUMERICHOST | NI_NUMERICSERV))
          {
            printf("Accepted connection on descriptor %d "
                   "(host=%s, port=%s)\n",
                   infd, hbuf, sbuf);
          }

          sco_t *socket_connect = (sco_t *)malloc(sizeof(sco_t));
          socket_connect_obj_init(socket_connect, infd, epfd);

          event.data.ptr = (void *)socket_connect;
          event.events = EPOLLIN | EPOLLET;

          ep_add(epfd, infd, &event);
        }
      }
      /*接受数据*/
      else if (events[i].events & EPOLLIN)
      {
        char buff[1024];
        while (1) //循环读取数据，以确保将缓存中的数据全部读出
        {
          memset(buff, '\0', sizeof(buff));
          int ret = recv(sco->connfd, buff, sizeof(buff) - 1, 0);
          if (ret < 0)
          {
            //对于非阻塞IO，下面的条件成立表示数据已经全部读取完毕。
            //此后，epoll就能再次触发sockfd上的EPOLLIN事件。
            if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
            {
              printf("read later\n");
              break;
            }
            //close(sco->connfd);
            break;
          }
          else if (ret == 0)
          {
           // close(sco->connfd);
          }
          else
          {
            printf("get %d bytes of content: %s\n", ret, buff);
          }
        }
      }
      
      
      /*发送数据*/
      else if (events[i].events & EPOLLET)
      {
        log_info("something else EPOLLET \n");
      }


      else
      {
        log_info("something else happened \n");
      }
    }
  }
}

/******************************************************************************
* @Function:  
* @Discrible:   
* @Param:  
* @Return:   
* @Others: 
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20190416      V1.0          VINCENT            Create
* 
*******************************************************************************/
int socket_connect_obj_init(sco_t *sco, int connfd, int epvfd)
{
  sco->connfd = connfd;
  sco->epvfd = epvfd;
  sco->status = 0;

  return 1;
}

/******************************************************************************
* @Function:  
* @Discrible:   
* @Param:  
* @Return:   
* @Others: 
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20190416      V1.0          VINCENT            Create
* 
*******************************************************************************/
int socket_connect_obj_free(sco_t *sco)
{
  close(sco->connfd);
  free(sco);
  return 1;
  ;
}
/************************ (.cpp) END OF FILE ************************************/